package bitbot.md;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import bitbot.core.S;


public class PairExchangeData {
	
	private static final Map<String, PairExchangeData> s_cById = new HashMap<String, PairExchangeData>();
		
	private final Pair m_pair;
	private final Exchange m_exchange;
	private final String m_id;
	
	//md data
	private int m_subscribedMask;
	private Record m_rec;
	private DeepData m_deep;
	private TimeAndSales m_tos;
	
	private List<IMarketDataListener> m_listeners = new CopyOnWriteArrayList<IMarketDataListener>();
	
	public Pair getPair() {	return m_pair; }
	public Exchange getExchange() { return m_exchange;}
	public String id() { return m_id; }
	int subscribedMask() { return m_subscribedMask; }
	
	public static PairExchangeData get(Pair pair, Exchange exchange) {
		PairExchangeData result = null;
		synchronized (s_cById) {
			result = s_cById.get(id(pair,exchange));
			if(result==null) {
				result = new PairExchangeData(pair, exchange);
				s_cById.put(result.id(), result);
				MdManager.i().register(result);
			}
		}
		
		return result;
	}
	
	private PairExchangeData(Pair pair, Exchange exchange) {
		m_pair = pair;
		m_exchange = exchange;
		m_id = id(pair, exchange);
		
	}

	private static String id(Pair pair, Exchange exchange) {
		return pair + exchange.id();
	}
	
	public synchronized void subscribe(IMarketDataListener lst) {
		if(!m_listeners.contains(lst)) {
			m_listeners.add(lst);
			m_subscribedMask |= lst.type().getMaskBit();
			MdManager.i().subscribed(this, lst.type());
		};
		
	}
	
	public synchronized void unsubscribe(IMarketDataListener lst) {
		m_listeners.remove(lst);
		boolean unsubscribe = true;
		for (IMarketDataListener listener : m_listeners) {
			if(listener.type()==lst.type()){
				unsubscribe = false;
				break;
			}
		}
		
		if(unsubscribe){
			m_subscribedMask &= ~lst.type().getMaskBit();
			MdManager.i().unsubscribe(this, lst.type());
		};
		
	}
	
	void onMarketData(MarketData md) {
		MarketDataType type = md.type();
		switch (type) {
			case TOP:
				m_rec = (Record) md;
				break;
			case DEEP:
				m_deep = (DeepData) md;
				break;
			case TIME_AND_SALES:
				m_tos = (TimeAndSales) md;
				break;	
			default:
				S.err("Unknown md " + md);
				break;
		}
		
		for (IMarketDataListener listener : m_listeners) {
			if(listener.type()==md.type()){
				listener.onUpdate(this, md);
			}
		}
	}

		
}
